﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Drawing;

namespace Stl.Controls
{
    /// <summary>
    /// Manager de Undo/Redo
    /// </summary>
    [ToolboxBitmap(typeof(DesignThrash), "DesignThrash.bmp")]
    public partial class DesignThrash : Component
    {
        /// <summary>
        /// Constructeur.
        /// </summary>
        public DesignThrash()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Constructeur qui prend un conteneur.
        /// </summary>
        /// <param name="container"></param>
        public DesignThrash(IContainer container)
        {
            container.Add(this);            
            InitializeComponent();
        }

        /// <summary>
        /// Liste de commandes qu'on peut undo.
        /// </summary>
        protected Stack<IUndo> undoStack = new Stack<IUndo>();
        /// <summary>
        /// Liste de commandes qu'on peut redo.
        /// </summary>
        protected Stack<IRedo> redoStack = new Stack<IRedo>();

        /// <summary>
        /// Possibilité de undo.
        /// </summary>
        public bool CanUndo
        {
            get { return undoStack.Count > 0; }
        }

        /// <summary>
        /// Possibilité de redo.
        /// </summary>
        public bool CanRedo
        {
            get { return redoStack.Count > 0; }
        }

        /// <summary>
        /// Getter de la pile de undo.
        /// </summary>
        public Stack<IUndo> UndoStack
        {
            get { return undoStack; }
        }

        /// <summary>
        /// Getter de la pile de redo.
        /// </summary>
        public Stack<IRedo> RedoStack
        {
            get { return redoStack; }
        }

        /// <summary>
        /// Ajoute une commande dans le manager.
        /// </summary>
        /// <param name="cmd"></param>
        public void Add(Command cmd)
        {
            undoStack.Push(cmd);
            redoStack.Clear();
            OnTrashChanged();
        }

        /// <summary>
        /// Undo
        /// </summary>
        public void Undo()
        {
            if (UndoStack.Count > 0)
            {
                IUndo cmd = UndoStack.Pop();
                cmd.Undo();
                redoStack.Push(cmd as Command);
                OnTrashChanged();
            }
        }

        /// <summary>
        /// Redo
        /// </summary>
        public void Redo()
        {
            if (redoStack.Count > 0)
            {
                IRedo cmd = RedoStack.Pop();
                cmd.Redo();
                UndoStack.Push(cmd as Command);
                OnTrashChanged();
            }
        }

        /// <summary>
        /// Lancée si une modification a eu lieu dans une des deux listes de commandes.
        /// </summary>
        public event EventHandler TrashChanged;

        /// <summary>
        /// Appélée lorsque les éléments de redo/undo ont changés.
        /// </summary>
        private void OnTrashChanged()
        {
            if(TrashChanged != null)
                TrashChanged(this, new EventArgs());
        }
    }
}
